#include "Mp4ClientStream.h"
#include "mediaPriv.h"
#include "VideoDecode.h"
#include "StreamerCurtainPlay.h"
#include "BgmCurtainPlay.h"

namespace Media {

std::map<Mp4StreamType, Mp4ClientStream*>   Mp4ClientStream::sm_streamMap;
std::recursive_mutex 		                Mp4ClientStream::sm_mapMutex;


Mp4ClientStream* Mp4ClientStream::instance(Mp4StreamType type)
{
	std::lock_guard<std::recursive_mutex> guard(sm_mapMutex);

	if (sm_streamMap.find(type) == sm_streamMap.end())
	{
		sm_streamMap[type] = new Mp4ClientStream(type);
	}

	return sm_streamMap[type];
}

Mp4ClientStream::Mp4ClientStream(Mp4StreamType type)
{
	m_taskTimer.reset();
	m_streamType = type;

	m_streamInThread.start([this](Fdt::Thread* thread) {this->StreamInProc(thread); }); //启动单独线程处理流
}

bool Mp4ClientStream::setAudioDecode(int channel, int frequency, int depth)
{
    ///创建音频输入管理对象
    if(!m_started_audio)
    {
        if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY))
        {
            m_pAudioDecode = AudioDecode::instance(m_audioChannel);
            if (!m_pAudioDecode)
            {
                errorf("m_pAudioDecode is NULL \n");
                return false;
            }

            AudioDecFormat decFormat = { 0 };
            decFormat.type = audioEncAAC;
            decFormat.frequency = frequency;
            decFormat.depth = depth;   
            decFormat.channels = channel;     

            LOG_PrintInfo("setAudioDecode:depth %d  channel : %d frequency: %d\n", decFormat.depth, decFormat.channels, decFormat.frequency);

            if (!m_pAudioDecode->setFormat(&decFormat))
            {
                errorf("AudioDecode setFormat error\n");
                return false;
            }

            if (!m_pAudioDecode->start())
            {
                errorf("AudioDecode start error\n");
                return false;
            }
        }

        m_started_audio = true;
    }
    return true;
}

bool Mp4ClientStream::setVideoDecode(VideoEncType type)
{
    if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY))
    {
        m_pVideoDecode = VideoDecode::instance(m_videoChannel);

        if (!m_pVideoDecode)
        {
            errorf("m_videoDecoder is NULL \n");
            return false;
        }

        VideoDecFormat decFormat;
        memset(&decFormat, 0, sizeof(VideoDecFormat));              
        decFormat.type = m_videoEncType;
        
        if (!m_pVideoDecode->setFormat(&decFormat))
        {
            errorf("m_pVideoDecode setFormat failed\n");
            return false;
        }

        if (!m_pVideoDecode->start())
        {
            errorf("m_pVideoDecode start failed\n");
            return false;
        }
    }    

    return true;
}

bool Mp4ClientStream::start(StreamPlayInfo playInfo)
{
    tracef("m_streamType:%d, playInfo.videoChn:%d, playInfo.audioChn:%d, content:%s\n", 
            m_streamType, playInfo.videoChn, playInfo.audioChn, playInfo.stream.content);
    if (!m_started)
    {
        m_playAbility = playInfo.playAbility;
        
        ///设置音视频解码通道
        if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY))
        {
            if (m_videoChannel != playInfo.videoChn)
            {
                m_videoChannel = playInfo.videoChn;
            }           
        }

        if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY))
        {
            if (m_audioChannel != playInfo.audioChn)
            {
                
                m_audioChannel = playInfo.audioChn; 
            }
        }

        ///创建Mp4 paly服务
        m_mp4Conent = playInfo.stream.content;

        if(m_streamType == MP4_ONLINE_STREAMER || m_streamType == MP4_ONLINE_BGM)
        {
            m_mp4Client = FrameCommon::CreateHttpMp4Player(m_mp4Conent.c_str(), false); //false

            tracef("m_mp4Client CreateHttpMp4Player success, content=%s\n", m_mp4Conent.c_str());
        }
        else if(m_streamType == MP4_LOCAL_STREAMER || m_streamType == MP4_LOCAL_BGM)
        {
            m_mp4Client = FrameCommon::CreateFileMp4Player(m_mp4Conent.c_str(), m_mp4RepetInfo ); //m_mp4RepetInfo

            tracef("m_mp4Client CreateFileMp4Player success, content=%s\n", m_mp4Conent.c_str());
        }
        
        if(!m_mp4Client)
        {
            errorf("m_mp4Client is NULL \n");
            return false;
        }

        ///按任务启动流
        m_taskInfo = playInfo.task;
        m_taskTimer.reset(new Fdt::Timer(m_taskInfo.StartTime * 1000, ([this]() {return this->streamStart(); }), nullptr));
        
        m_started = true;

        m_dropFrame = true;
    }
    else
    {
        tracef("m_mp4Client has started\n");
    }   

    return true;
}

bool Mp4ClientStream::stop()
{
    tracef("m_mp4Client m_streamType:%d stop enter, m_started:%d\n", m_streamType, m_started);
    if (m_started)
    {
        streamStop();
        
        if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY))
        {
            if (!m_pVideoDecode || !m_pVideoDecode->stop())
            {
                return false;
            }
        }
        
        if(m_started_audio){
            if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY))
            {
                if (!m_pAudioDecode || !m_pAudioDecode->stop())
                {
                    return false;
                }
            }
        }
        
        m_started = false;
        m_vpnAddr = "";
        m_started_audio = false;
        m_queueMutex.lock();
        while (!m_frameaQueue.empty()) m_frameaQueue.pop();
        m_queueMutex.unlock();
    }

    clearVideoQueue();

    m_dropFrame = false;

     tracef("m_mp4Client leave\n");

    return true;
}

bool Mp4ClientStream::streamStop(void)
{
    if(m_mp4Client)
    m_mp4Client.reset();
    return true;
}

bool Mp4ClientStream::SaveToCommQueue(FramePtr& msg)
{
    if (msg.get() != NULL && m_frameaQueue.size() < QueueSize)
    {
        m_queueMutex.lock();

        m_frameaQueue.push(msg);

        m_queueMutex.unlock();
    }
    else
    {
        LOG_PrintInfo("saveToCommQueue::enter [%s] [%d] qsize=%d\n", __FILE__, __LINE__, m_frameaQueue.size());
        
        m_queueMutex.lock();
        m_frameaQueue.front();//处理队列中消息,移除最早的数据	
        m_frameaQueue.pop();
        m_queueMutex.unlock();
    }
    return true;
}

bool Mp4ClientStream::GetCommQueueMsg(FramePtr& msg)
{
    m_queueMutex.lock();
    if (!m_frameaQueue.empty())
    {
        msg = m_frameaQueue.front();//处理队列中消息		
        m_frameaQueue.pop();

        //printf("enter [%s] [%d] \n",__FILE__,__LINE__);
        m_queueMutex.unlock();
        return true;
    }
    m_queueMutex.unlock();
    return false;
}

bool Mp4ClientStream::clearVideoQueue()
{
    m_queueMutex.lock();
    while (!m_frameaQueue.empty()) m_frameaQueue.pop();
    m_queueMutex.unlock();

    return true;
}

void Mp4ClientStream::StreamInProc(Fdt::Thread* thread)
{
    thread->setPriority(Fdt::PRIORITY_NORMAL, Fdt::POLICY_RR);

    //printf("enter [%s] [%d] \n",__FILE__,__LINE__);

    uint64_t lastTime = vdo_get_time();

    int      frameProcTime = 30;

    int      disConnTime = 1000;

#if 1
    FramePtr framePtr;

    while (thread->running())
    {
        if (!GetCommQueueMsg(framePtr))
        {
            thread->sleep(3);
            continue;
        }

        sendVideoPacket(framePtr->data, framePtr->size, framePtr->timestamp);

        uint64_t runtime = vdo_get_time() - lastTime;
        if (runtime < frameProcTime)
        {
            thread->sleep(frameProcTime - runtime);
        }
        else if (runtime > disConnTime) //下一次连接
        {
            thread->sleep(frameProcTime);

            //LOG_PrintWarn("ScreenMirrorStream ::StreamInProc  over maxFreq runtime=%llu, maxFreq=%u\n", runtime, maxFreq);
        }



        lastTime = vdo_get_time();

    }
#endif

}


bool Mp4ClientStream::onFrame(const FrameCommon::Frame::Ptr& frame)
{
    auto id = frame->codecId();
    //LOG_PrintWarn("id :%d \n", id);
    if (frame->isVideo()
      && ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY)))
    {
#if 1
        char* data = frame->data();

        if (data[0] == 0 && data[1] == 0 && data[2] == 0
            && data[3] == 1 && (data[4] == H264_NALU_AUD || data[4] == H264_NALU_SEI)) {
            
                        return false;
        }

        if(m_dropFrame && (m_videoEncType == videoEncH264))
        {       
            if(frame->size() > 4)
            {
                int frameType = data[4] & 0x1F;
                if(0x07 == frameType) //SPS
                {
                    m_dropFrame = false;
                    LOG_PrintWarn("Mp4ClientStream::onVideoFrame videoEncH264 dropFrame done\n");
                }
                else
                {
                                        return false;
                }
            }
            else
            {
                                return false;
            }
        }
        else if(m_dropFrame && (m_videoEncType == videoEncH265))
        {       
            if(frame->size() > 4)
            {
                int frameType = ((data[4] >> 1) & 0x3f);
                if (0x20 == frameType) //VPS/SPS/PPS/IDR合并发过来
                {
                    m_dropFrame = false;
                    LOG_PrintWarn("Mp4ClientStream::onVideoFrame videoEncH265 dropFrame done\n");
                }
                else
                {
                    //LOG_PrintWarn("Mp4ClientStream::onVideoFrame frameType=%d\n", frameType);
                    return false;
                }
            }
            else
            {
                                 return false;
            }
        }

#endif  
       
        FramePtr videoFrame(new FrameBuffer(frame->size()));
        videoFrame->timestamp = frame->pts();
        videoFrame->size = frame->size();
        memcpy(videoFrame->data, frame->data(), frame->size());
        SaveToCommQueue(videoFrame);
    }
    else if (frame->isAudio()
      && ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY)))
    {
        //media_FILE_Write("/tmp/gan.aac", frame->data(), frame->size());
        sendAudioPacket((unsigned char*)frame->data(), frame->size());
    }
        
    return true;
}

bool Mp4ClientStream::onStop()
{
    tracef("Mp4ClientStream onStop enter\n");

    if(m_streamType == MP4_ONLINE_STREAMER || m_streamType == MP4_LOCAL_STREAMER)
    {
        StreamerCurtainPlay::instance()->playNextStreamer();
    }
    else
    {
        BgmCurtainPlay::instance()->playNextBgm();
    }
    return true;
}

bool Mp4ClientStream::setVpnAddr(std::string& vpnAddr)
{
    int len = vpnAddr.length();
    if (len <= 0)
    {
        //LOG_PrintError("Mp4ClientStream vpnAddr length <= 0");
        return false;
    }

    m_vpnAddr = "";
    m_vpnAddr.assign((char*)vpnAddr.c_str());
    return true;
}

void Mp4ClientStream::getAudioInfo(const FrameCommon::AudioFormat& frame)
{
    int depth     = frame.depth;//16
    int channel   = frame.channel;  //2
    int frequency = frame.sampleRate; //44100
    LOG_PrintInfo("depth %d  channel : %d frequency: %d\n", depth, channel, frequency);

    if (frequency <= 0 || depth <= 0 || channel <= 0) 
    {
         LOG_PrintError("getAudioInfo params error\n");    
         return;
    }
    
    setAudioDecode(channel, frequency, depth);
}

void Mp4ClientStream::getVideoInfo(const FrameCommon::VideoFormat& frame)
{
    int type = frame.type;
    LOG_PrintInfo("getVideoInfo type: %d\n", type);

    if(type == FrameCommon::H265)
    {              
        m_videoEncType = videoEncH265;        
    }
    else
    {
        m_videoEncType = videoEncH264;
    }

    setVideoDecode(m_videoEncType);
}

bool Mp4ClientStream::streamStart()
{
    if(!m_mp4Client)
    {
        errorf("m_mp4Client is NULL \n");
        return false;
    }
    if (m_streamType == MP4_ONLINE_STREAMER && m_vpnAddr.length() > 0)
    {
        m_mp4Client->SetProxy(m_vpnAddr);
    }

    if((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY))
    m_mp4Client->SetVideoReady([this](const FrameCommon::VideoFormat& frame) { getVideoInfo(frame); });
    
    if ((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY))
    m_mp4Client->SetAudioReady([this](const FrameCommon::AudioFormat& frame) { getAudioInfo(frame); });
    
    bool iRet = m_mp4Client->Play([this](const FrameCommon::Frame::Ptr& frame) {return onFrame(frame); }, [this]() { onStop(); });
    if(!iRet)
    {
        errorf("m_mp4Client Play failed\n");
    }
    else
    {
        tracef("m_mp4Client Play success\n");
    }

    if (m_taskInfo.StopTime != -1)
    {
        m_taskTimer.reset(new Fdt::Timer(m_taskInfo.StopTime * 1000, ([this]() {return this->stop(); }), nullptr)); //不是循环播放，注册停止函数
    }
    else
    {
        m_taskTimer.reset();
    }

    return true;
}

bool Mp4ClientStream::sendVideoPacket(unsigned char* buffer, int buflen, uint64_t timestamp)
{
    if (m_pVideoDecode)
    {
        m_videoPacket.buffer = buffer;
        m_videoPacket.length = buflen;
        m_videoPacket.pts = timestamp;

        //LOG_PrintWarn("sendVideoPacket CALL");

        return m_pVideoDecode->putPacket(&m_videoPacket);
    }
    return false;
}

bool Mp4ClientStream::sendAudioPacket(unsigned char* buffer, int buflen)
{
    if (m_pAudioDecode)
    {
        //LOG_PrintWarn("buflen :%d", buflen);
        m_audioPacket.buffer = buffer;
        m_audioPacket.length = buflen;

        return m_pAudioDecode->putPacket(&m_audioPacket);
    }
    else {
        LOG_PrintError("m_pAudioDecode is nullptr");
    }

    return false;
}

bool Mp4ClientStream::setRepetInfo(bool repet)
{
    tracef("m_mp4Client setRepetInfo repet=%d\n", repet);
    
    m_mp4RepetInfo = repet;
    return true;
}


}